package com.javaspeak.designpatterns.go4.behavioural.memento;

import java.util.Deque;
import java.util.LinkedList;

/**
 * This example uses the Memento pattern for undo operations. In the Memento
 * pattern there is a Caretaker, Originator and Memento.
 * <p>
 * The Originator is the class that has state that needs to be rolled back
 * to the previous version.   The Caretaker manages the backup and restoration
 * of state to the Originator.  The Caretaker asks the Originator for a
 * Memento object that holds a snapshot of its current state. The Caretaker
 * then adds this to a Deque (LIFO queue) it is managing.  Later on an undo
 * operation involves taking the last Memento put on the LIFO queue and passing
 * it to the Originator so that the Originator has the information to roll back
 * its state to the last saved version.
 * <p>
 * In this example we are modelling the saving operation of a text editor.
 * Everytime  the document is saved the Caretaker (ApplicationMemento) asks the
 * Originator (DocumentImpl) for a DocumentMemento which it adds to a
 * momentoDeque (LIFO queue).  After saving 3 times and printing the saved text
 * to the console an undo operation is called two times (restoreFromMemento()).
 * After each undo operation the document text is printed to the console so you
 * can see that the multiple undo has worked.
 *
 * @author John Dickerson
 */
public class ApplicationMemento implements Caretaker {

    private Document document = new DocumentImpl();
    private Deque<Memento> momentoDeque = new LinkedList<Memento>();

    /* (non-Javadoc)
     * @see com.javaspeak.designpatterns.go4.behavioural.memento.
     *      Caretaker#saveMemento(com.javaspeak.designpatterns.go4.behavioural.
     *          memento.Memento)
     */
    @Override
    public void saveMemento( Memento memento ) {

        momentoDeque.offerLast( memento );
    }

    /* (non-Javadoc)
     * @see com.javaspeak.designpatterns.go4.behavioural.memento.
     *      Caretaker#restoreFromMemento()
     */
    @Override
    public void restoreFromMemento() {

        momentoDeque.removeLast();
        Memento lastSavedMemento = momentoDeque.peekLast();
        document.restoreFromMemento( lastSavedMemento );
    }


    /**
     * Runs the example application.  This application is modelling a the saving
     * operation of a text application. Note that the document has: font family,
     * font size and document text properties but the DocumentMemento only
     * saves the document text state.  This is because we only want to undo text
     * edits and not change of font size or font family edits.
     * <p>
     * Every time we call saveDocumentText(..) on the Document we also call the
     * saveMemento(..) method to save the documentText in a DocumentMemento
     * object and place it at the end of a deque (LIFO queue).
     * <p>
     * Everytime we ant to undo a text operation we remove the last
     * DocumentMemento off the end of the Deque and read the last
     * DocumentMemento still remaining on the the end of the Deque.  We then
     * use this DocumentMemento to roll back the state of the Document.
     */
    public void runExample(){

        document.saveFontFamily( "arial" );
        document.saveFontSize( 12 );

        document.saveDocumentText( "Hello World!" );
        saveMemento( document.getMemento() );

        document.saveDocumentText(
              document.getDocumentText() +
                    " Saving a Second Time." );

        saveMemento( document.getMemento() );

        document.saveDocumentText(
                document.getDocumentText() +
                      " Saving a Third Time." );

        saveMemento( document.getMemento() );

        System.out.println( "===============================================" );

        System.out.println( document.getDocumentText() );

        System.out.println( "===============================================" );

        restoreFromMemento();

        System.out.println(  document.getDocumentText() );

        System.out.println( "===============================================" );

        restoreFromMemento();
        System.out.println( document.getDocumentText() );

        System.out.println( "===============================================" );
    }

    /**
     * @param args
     */
    public static void main(String[] args) {

        ApplicationMemento applicationMemento = new ApplicationMemento();
        applicationMemento.runExample();
    }

}
